package qf.index;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import cn.hutool.json.JSONUtil;
import lombok.Data;

import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * C1中的作者是全写，RP中的作者是简写，为了让其均为C1中的全写，特写此程序。主方法为：rpChangeC1(c1List, rpList)，返回新的rpList。
 * 贾新志 2024.11.12
 */
public class ChangeRp {

    public static void main(String[] args) throws SQLException {

        String chinaHospTestTable = "scholar_25_01.tb_true_china_hosp_6_year_test";
        testRpChangeC1(chinaHospTestTable, "id", "C1`,`RP");

    }

    public static void testRpChangeC1(String chinaHospTestTable, String autoId, String field) throws SQLException {
        // 测试RpChangeC1程序，使用约1800万的中国医院的数据进行测试。
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        int onePageNum = 1000;
        List<Entity> tableNum = Db.use().query("select count(1) as count from " + chinaHospTestTable);
        if (tableNum.get(0).getInt("count") > 0) {
            int tableMax = Db.use().queryNumber("select max(" + autoId + ") from " + chinaHospTestTable).intValue();
            Collection<Integer> tableList = new ArrayList<>();
            NumberUtil.appendRange(0, tableMax + onePageNum, onePageNum, tableList);
            for (Integer startId : tableList) {
                List<Entity> tableData = Db.use().query("select `" + autoId + "`,`" + field + "` from " + chinaHospTestTable + " where " + autoId + " between " + startId + " and " + (startId + onePageNum - 1));
                System.out.println("\033[31;1m" + format.format(new Date()) + " 读表现在开始：" + startId + " 表名：" + chinaHospTestTable + Utils.printMemoryStr() + "\033[0m");
                for (Entity entry : tableData) {
                    int id = Utils.getIntField(entry, autoId);
                    List<En.C1Auth> rpList = Utils.getRpList(entry.getStr("RP"));
                    List<En.C1Auth> c1List = Utils.getC1List(entry.getStr("C1"));
                    List<En.C1Auth> changeRp = ChangeRp.rpChangeC1(c1List, rpList);
                    Set<String> c1Set = ChangeRp.getAuthSet(c1List);
                    Set<String> rpSet = ChangeRp.getAuthSet(changeRp);
                    boolean bool = false;
                    for (String s : rpSet) {
                        if (!c1Set.contains(s)) {
                            bool = true;
                            break;
                        }
                    }
                    try {
                        Db.use().update(Entity.create().set("c1_list", JSONUtil.toJsonStr(c1List)).set("rp_list", JSONUtil.toJsonStr(rpList)).set("change_rp", JSONUtil.toJsonStr(changeRp)).set("is_ok", bool ? 0 : 1), Entity.create(chinaHospTestTable).set(autoId, id));
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public static Set<String> getAuthSet(List<En.C1Auth> c1List) {
        Set<String> authSet = new HashSet<>();
        for (En.C1Auth authListAndInfo : c1List) {
            List<String> authList = changeAuthList(authListAndInfo.getAuthList());
            for (String s : authList) {
                authSet.add(Utils.dellEnd(s.toLowerCase().trim()));
            }
        }
        return authSet;
    }

    public static List<String> changeAuthList(List<String> c1AuthList) {
        // 对于只有空格而没有逗号的作者加上逗号
        List<String> result = new ArrayList<>();
        for (String auth : c1AuthList) {
            auth = Utils.dellEnd(auth);
            if (auth.contains(" ") && !auth.contains(",")) {
                int i = auth.indexOf(" ");
                String r = auth.substring(0, i) + ", " + auth.substring(i);
                result.add(r.replaceAll(" +", " ").trim());
            } else {
                result.add(auth);
            }
        }
        return result;
    }

    /**
     * 以上为测试中使用到的方法，以下为转换的主方法。
     */

    public static List<En.C1Auth> rpChangeC1(List<En.C1Auth> c1List, List<En.C1Auth> rpList) {
        // rp中的简写作者转换为c1中的全写作者的主方法，此程序下还包括rpChangeC1Again、getBestAuth、selectC1Len、selectC1StartsWith、getSimilarityRatio等
        List<En.C1Auth> resultList = new ArrayList<>();
        Map<String, Set<String>> c1InfoAndAuthSetMap = new HashMap<>();
        Map<String, Set<String>> rpAuthAndInfoSetMap = new HashMap<>();
        Set<String> c1AuthSet = new HashSet<>();
        for (En.C1Auth c1Auth : rpList) {
            List<String> rpAuthList = c1Auth.getAuthList();
            String rpInfo = c1Auth.getInfo();
            List<String> rpAuths = new ArrayList<>();
            for (String rpAuth : rpAuthList) {
                String result = "";
                for (En.C1Auth c1 : c1List) {
                    List<String> c1AuthList = c1.getAuthList();
                    String c1Info = c1.getInfo();
                    if (rpInfo.equalsIgnoreCase(c1Info)) {
                        String c1Au = getC1Auth(rpAuth, c1AuthList);
                        if (!c1Au.isEmpty()) {
                            result = c1Au;
                            break;
                        }
                    } else {
                        String c1Au = getC1Auth(rpAuth, c1AuthList);
                        if (!c1Au.isEmpty()) {
                            result = c1Au;
                            break;
                        }
                    }
                    for (String s : c1AuthList) {
                        c1AuthSet.add(s);
                        Utils.putStrSetStr(c1Info, s, c1InfoAndAuthSetMap);
                    }
                }
                rpAuths.add(result.isEmpty() ? rpAuth : result);
                Utils.putStrSetStr(result.isEmpty() ? rpAuth : result, rpInfo, rpAuthAndInfoSetMap);
            }
            En.C1Auth rC1Auth = new En.C1Auth();
            rC1Auth.setAuthList(rpAuths);
            rC1Auth.setInfo(rpInfo);
            rC1Auth.setFull(c1Auth.getFull());
            rC1Auth.setSort(c1Auth.getSort());
            resultList.add(rC1Auth);
        }
        return rpChangeC1Again(resultList, c1InfoAndAuthSetMap, rpAuthAndInfoSetMap, c1AuthSet);
    }

    public static String getC1Auth(String rpAuth, List<String> c1AuthList) {
//        List<String> authList = changeAuthList(c1AuthList);
        if (rpAuth.contains(", ") && !rpAuth.startsWith(", ") && !rpAuth.endsWith(" ,")) {
            rpAuth = Utils.dellEnd(rpAuth);
            String rpAu = rpAuth.replaceAll(" +", " ").toLowerCase().trim();
            String[] rpSplit = rpAu.split(", ");
            if (rpSplit.length == 2) {
                String rpFront = rpSplit[0];
                String rpEnd = rpSplit[1];
                for (String c1Auth : c1AuthList) {
                    c1Auth = Utils.dellEnd(c1Auth);
                    String c1Au = c1Auth.replaceAll(" +", " ").toLowerCase().trim();
                    String[] c1Split = c1Au.split(", ");
                    if (c1Split.length == rpSplit.length) {
                        String c1Front = c1Split[0];
                        String c1End = c1Split[1];
                        if (rpFront.equals(c1Front)) {
                            c1End = c1End.contains(" ") ? c1End.replace("-", " ").replaceAll(" +", " ").trim() : c1End;
                            String[] c1EndSplit = c1End.split(" ");
                            if (c1EndSplit.length == rpEnd.length()) {
                                StringBuilder c1EndFirst = new StringBuilder();
                                for (String s : c1EndSplit) {
                                    if (null != s && !s.isEmpty()) {
                                        s = s.startsWith("-") ? s.substring(1) : s;
                                        c1EndFirst.append(s.charAt(0));
                                    }
                                }
                                // Chung, Brian Hon Yin->Chung, BHY
                                if (c1EndFirst.toString().equals(rpEnd)) {
                                    return c1Auth;
                                }
                            } else if (!rpEnd.isEmpty() && !c1End.contains(" ") && c1End.length() >= rpEnd.length() && c1End.startsWith(rpEnd.substring(0, 1))) {
                                String[] split = rpEnd.split("");
                                boolean bool = true;
                                // Chung, BrianHonYin->Chung, BHY
                                for (int i = 0; i < split.length; i++) {
                                    if (!c1End.substring(i).contains(split[i])) {
                                        bool = false;
                                        break;
                                    }
                                }
                                if (bool) {
                                    return c1Auth;
                                }
                            }
                        }
                    }
                }
            }
        }
        return "";
    }

    public static String getBestAuth(String c1Auth, double score, String rpAuth, Set<String> c1AuthSet) {
        // 获取匹配度最高的作者，如果两个作者之间的相似度大于0.56直接认定是同一个人。如果姓相同（逗号前面的），且简写的每一个字符均是全写的词的首字母，也认定为是同一个人。
        String rp = rpAuth.toLowerCase().replace("à", "a").replace("á", "a").replace("â", "a").replace("ã", "a").replace("ä", "a").replace("å", "a")
                .replace("è", "e").replace("é", "e").replace("ê", "e").replace("ë", "e").replace("ì", "i").replace("í", "i").replace("î", "i")
                .replace("ï", "i").replace("ñ", "n").replace("ò", "o").replace("ó", "o").replace("ô", "o").replace("ö", "o").replace("ù", "u")
                .replace("ú", "u").replace("û", "u").replace("ü", "u").replace("ÿ", "y").replace("ç", "c").replace("æ", "ae");
        if (score > 0.56) {
            return c1Auth;
        }
        rp = !rp.contains(",") && rp.length() > 5 ? (rp + ",lllll") : rp;
        if (rp.contains(",") && !rp.startsWith(",")) {
            String selectC1Auth = selectC1Auth(rp, c1Auth, false);
            // 如果提供的指定的c1（这里的c1是与rp单位信息相同的c1）不能匹配的到，进一步扩大到所有的c1AuthSet集合。
            if (!selectC1Auth.isEmpty()) {
                return selectC1Auth;
            } else {
                for (String c1 : c1AuthSet) {
                    if (!selectC1Auth(rp, c1, false).isEmpty()) {
                        return c1;
                    }
                }
            }
            String lenAuth = selectC1Len(rp, c1AuthSet);
            if (!lenAuth.isEmpty()) {
                return lenAuth;
            }
            String startsWith = selectC1StartsWith(rp, c1AuthSet);
            if (!startsWith.isEmpty()) {
                return startsWith;
            }
//            System.out.println("----rp: |" + rp + "| c1AuthSet:" + c1AuthSet);
            // 由于存在.replace("ä", "ae").replace("ü", "ue").replace("ö", "oe")，所以又作了一次
            rp = rpAuth.toLowerCase().replace("à", "a").replace("á", "a").replace("â", "a").replace("ã", "a").replace("ä", "ae").replace("å", "a")
                    .replace("è", "e").replace("é", "e").replace("ê", "e").replace("ë", "e").replace("ì", "i").replace("í", "i").replace("î", "i")
                    .replace("ï", "i").replace("ñ", "n").replace("ò", "o").replace("ó", "o").replace("ô", "o").replace("ö", "oe").replace("ù", "u")
                    .replace("ú", "u").replace("û", "u").replace("ü", "ue").replace("ÿ", "y").replace("ç", "c").replace("æ", "ae");
            rp = !rp.contains(",") && rp.length() > 5 ? (rp + ",lllll") : rp;
            selectC1Auth = selectC1Auth(rp, c1Auth, true);
            // 如果提供的指定的c1（这里的c1是与rp单位信息相同的c1）不能匹配的到，进一步扩大到所有的c1AuthSet集合。
            if (!selectC1Auth.isEmpty()) {
                return selectC1Auth;
            } else {
                for (String c1 : c1AuthSet) {
                    if (!selectC1Auth(rp, c1, true).isEmpty()) {
                        return c1;
                    }
                }
            }
            lenAuth = selectC1Len(rp, c1AuthSet);
            if (!lenAuth.isEmpty()) {
                return lenAuth;
            }
            startsWith = selectC1StartsWith(rp, c1AuthSet);
            if (!startsWith.isEmpty()) {
                return startsWith;
            }
        }
        return rpAuth;
    }

    public static List<En.C1Auth> rpChangeC1Again(List<En.C1Auth> rpList, Map<String, Set<String>> c1InfoAndAuthSetMap, Map<String, Set<String>> rpAuthAndInfoSetMap, Set<String> c1AuthSet) {
        // 再次转换。如果rp中的作者没有在c1列表中，说明rp是不对的，先获取rp对应的info集合，再判断各info是否在c1的info内，如果在则说明两个info是相同的，此时再判断info相同的情况下两个作者之间的最高相似度，理论上如果两个作者的info相同，只要两个作者的相似度大于0.45即可以判定为同一个人。
        List<En.C1Auth> resultList = new ArrayList<>();
        for (En.C1Auth authListAndInfo : rpList) {
            List<String> rpAuthList = authListAndInfo.getAuthList();
            String rpInfo = authListAndInfo.getInfo();
            List<String> rpAuths = new ArrayList<>();
            for (String rpAuth : rpAuthList) {
                String c1Auth = "";
                double score = 0.0;
                if (!c1AuthSet.contains(rpAuth) && rpAuthAndInfoSetMap.containsKey(rpAuth)) {
                    Set<String> infoSet = rpAuthAndInfoSetMap.get(rpAuth);
                    for (String info : infoSet) {
                        if (c1InfoAndAuthSetMap.containsKey(info)) {
                            Set<String> authSet = c1InfoAndAuthSetMap.get(info);
                            for (String auth : authSet) {
                                double similarityRatio = Utils.getSimilarityRatio(auth, rpAuth);
                                if (similarityRatio > score) {
                                    score = similarityRatio;
                                    c1Auth = auth;
                                }
                            }
                        }
                    }
                }
//                System.out.println("score: " + score + " result: " + c1Auth + " rpAuth: " + rpAuth);
                // 如果两个作者的info相同，若两个作者之间的相似度大于0.56即可以判定为同一个人。
                rpAuths.add(getBestAuth(c1Auth, score, rpAuth, c1AuthSet));
            }
            En.C1Auth resutlAuthListAndInfo = new En.C1Auth();
            resutlAuthListAndInfo.setAuthList(rpAuths);
            resutlAuthListAndInfo.setInfo(rpInfo);
            resutlAuthListAndInfo.setFull(authListAndInfo.getFull());
            resutlAuthListAndInfo.setSort(authListAndInfo.getSort());
            resultList.add(resutlAuthListAndInfo);
        }
        return resultList;
    }

    public static String selectC1StartsWith(String rp, Set<String> c1AuthSet) {
        // 如果rp中的每一个单词，均是c1中的开头，则也可以认定为同一个作者。
        String[] rpSplit = rp.replace(",", " ").replace("  ", " ").split(" ");
        if (rpSplit.length > 1) {
            for (String c1 : c1AuthSet) {
                String[] c1Split = c1.toLowerCase().replace(",", " ").replace("  ", " ").split(" ");
                if (rpSplit.length == c1Split.length) {
                    boolean bool = true;
                    for (int i = 0; i < c1Split.length; i++) {
                        if (!c1Split[i].startsWith(rpSplit[i])) {
                            bool = false;
                            break;
                        }
                    }
                    if (bool) {
                        return c1;
                    }
                }
            }
        }
        return "";
    }

    public static String selectC1Len(String rp, Set<String> c1AuthSet) {
        // 匹配rp作者中最长的那个单词，是否在c1作者中存在，如果存在，且只存在一个作者中，可以认定为此作者。
        String[] split = rp.replace(",", " ").split(" ");
        String lenAuth = "";
        for (String s : split) {
            lenAuth = s.length() > lenAuth.length() ? s : lenAuth;
        }
        Set<C1SplitAndAuth> c1SplitAndAuthSet = new HashSet<>();
        for (String s : c1AuthSet) {
            C1SplitAndAuth c1SplitAndAuth = new C1SplitAndAuth();
            String[] c1Split = s.toLowerCase().replace(",", " ").replace("-", " ").replace(".", " ").replace("\\", " ").replace("]", " ").replace("_", " ")
                    .replace(")", " ").replace("+", " ").replace("/", " ").replace(":", " ").replace("}", " ").replace("?", " ").replace("©", " ")
                    .replace("(", " ").replace("{", " ").replace("[", " ").replaceAll(" +", " ").trim().split(" ");
            c1SplitAndAuth.setC1Auth(s);
            c1SplitAndAuth.setC1Split(c1Split);
            c1SplitAndAuthSet.add(c1SplitAndAuth);
        }
        int num = 0;
        String maxAuth = "";
        for (C1SplitAndAuth c1SplitAndAuth : c1SplitAndAuthSet) {
            String[] c1Split = c1SplitAndAuth.getC1Split();
            for (String c1 : c1Split) {
                if (c1.equals(lenAuth)) {
                    num++;
                    maxAuth = c1SplitAndAuth.getC1Auth();
                    break;
                }
            }
            if (num > 1) {
                break;
            }
        }
        if (num == 1) {
            return maxAuth;
        }
        return "";
    }

    public static String selectC1Auth(String rp, String c1Auth, boolean isDellBracket) {
        // 匹配c1作者，方法一，c1一位无空格，rp两位；方法二，c1两位，rp三位；方法三，每一个rp均是c1中一个单词的开头。
        if (null == c1Auth || c1Auth.isEmpty()) {
            return "";
        }
        String c1 = c1Auth.toLowerCase();
        c1 = (isDellBracket && c1.contains("(")) ? c1.substring(0, c1.indexOf("(")).trim() : c1;
//        System.out.println("~~~~rp:" + rp);
        String front = rp.substring(0, rp.indexOf(","));
//        System.out.println("1. rp: " + rp + " c1Auth: " + c1Auth + " front: " + front);
        if ((c1.startsWith(front + " ") || c1.endsWith(" " + front) || c1.startsWith(front + ",") || c1.endsWith("," + front) || c1.contains(" " + front + " ") || c1.contains(" " + front + ",") || c1.contains(" " + front + "-") ||
                c1.contains("-" + front + " ") || c1.contains(" " + front + ".") || c1.contains("." + front + " ") || c1.contains("," + front + " ") || c1.startsWith(front + ".") || c1.endsWith("." + front) || c1.startsWith(front + "-") || c1.endsWith("-" + front))) {
            String[] c1Split = c1.replaceFirst(front, " ").replace(",", " ").replace("-", " ").replace(".", " ").replace("\\", " ").replace("]", " ").replace("_", " ")
                    .replace(")", " ").replace("+", " ").replace("/", " ").replace(":", " ").replace("}", " ").replace("?", " ").replace("©", " ")
                    .replace("(", " ").replace("{", " ").replace("[", " ").replaceAll(" +", " ").trim().split(" ");
            String[] rpSplit = rp.substring(rp.indexOf(",") + 1).replaceAll(" +", "").replace(" ", "").split("");
//            System.out.println(c1Split.length + "==" + rpSplit.length + " c1: " + c1 + " rp: " + rp);
            int sum = 0;
            // c1: rao, savita   rp: rao, sv
            if (c1Split.length == 1 && rpSplit.length == 2 && c1Split[0].length() > 3) {
                if (c1Split[0].contains(rpSplit[0]) && c1Split[0].contains(rpSplit[1])) {
                    return c1Auth;
                }
            }
            // c1: rao, savita p   rp: rao, svp
            if (c1Split.length == 2 && rpSplit.length == 3) {
                String f = c1Split[0];
                String e = c1Split[1];
                if ((f.contains(rpSplit[0]) && f.contains(rpSplit[1]) && e.startsWith(rpSplit[2])) || (f.startsWith(rpSplit[0]) && e.contains(rpSplit[1]) && e.contains(rpSplit[2]))) {
                    return c1Auth;
                }
            }
            for (String end : rpSplit) {
                for (String s : c1Split) {
                    if (s.startsWith(end)) {
                        sum++;
                        break;
                    }
                }
            }
            if (sum == rpSplit.length) {
                return c1Auth;
            }
        }
        return "";
    }

    @Data
    public static class C1SplitAndAuth {
        private String[] c1Split;
        private String c1Auth = "";
    }


}
